﻿using MvvmCross.Core.ViewModels;
using Sidvall.Data;
using Sidvall.LogManager.UI.Entities;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Input;

namespace Sidvall.LogManager.UI.ViewModels
{
    public partial class LogScopeViewModel
    {
        #region Public Members

        #region Title

        private string _Title;
        public string Title
        {
            get
            {
                return _Title;
            }
            set
            {
                _Title = value;
                RaisePropertyChanged("Title");
            }
        }

        #endregion
        #region AddTreeItemCaption

        public string AddTreeItemCaption
        {
            get
            {
                if (this.ActiveServer != null)
                    return "Add Log Scope";
                return null;
            }
        }

        #endregion
        #region TreeItems

        private TreeItemCollection _TreeItems;
        public TreeItemCollection TreeItems
        {
            get
            {
                return _TreeItems;
            }
            set
            {
                _TreeItems = value;
                RaisePropertyChanged("TreeItems");
            }
        }

        #endregion
        #region LogScopeItems

        private LogScopeItemCollection _LogScopeItems;
        public LogScopeItemCollection LogScopeItems
        {
            get
            {
                return _LogScopeItems;
            }
            set
            {
                _LogScopeItems = value;
                RaisePropertyChanged("LogScopeItems");
            }
        }

        #endregion
        #region EventTypes

        private Sidvall.Data.KeyValueCollection<string, Sidvall.Logging.EventType> _EventTypes;
        public Sidvall.Data.KeyValueCollection<string, Sidvall.Logging.EventType> EventTypes
        {
            get
            {
                if (_EventTypes == null)
                    this.EventTypes = Sidvall.Data.KeyValueManager.FromEnum<Sidvall.Logging.EventType>();
                return _EventTypes;
            }
            set
            {
                _EventTypes = value;
                RaisePropertyChanged("EventTypes");
            }
        }

        #endregion
        #region Categories

        private System.Collections.ObjectModel.Collection<string> _Categories;
        public System.Collections.ObjectModel.Collection<string> Categories
        {
            get
            {
                return _Categories;
            }
            set
            {
                _Categories = value;
                RaisePropertyChanged("Categories");
            }
        }

        #endregion
        #region ActiveTreeItem

        private TreeItem _ActiveTreeItem;
        public TreeItem ActiveTreeItem
        {
            get
            {
                return _ActiveTreeItem;
            }
            set
            {
                _ActiveTreeItem = value;
                RaisePropertyChanged("ActiveTreeItem");
                InitializeTitle();
            }
        }

        #endregion
        #region ActiveServer

        private ServerConnection _ActiveServer;
        public ServerConnection ActiveServer
        {
            get
            {
                return _ActiveServer;
            }
            set
            {
                _ActiveServer = value;
                if (_ActiveServer != null)
                {
                    _ActiveLogScope = null;
                }
                InitializeTreeItem();
            }
        }

        #endregion
        #region ActiveLogScope

        private LogScope _ActiveLogScope;
        public LogScope ActiveLogScope
        {
            get
            {
                return _ActiveLogScope;
            }
            set
            {
                if (_ActiveLogScope != null)
                    _ActiveLogScope.PropertyChanged -= OnActiveLogScopePropertyChanged;
                _ActiveLogScope = value;
                if (_ActiveLogScope != null)
                {
                    _ActiveLogScope.PropertyChanged += OnActiveLogScopePropertyChanged;
                    _ActiveServer = null;
                }
                InitializeTreeItem();
            }
        }

        #endregion
        #region ActiveLogScopeItem

        private LogScopeItem _ActiveLogScopeItem;
        public LogScopeItem ActiveLogScopeItem
        {
            get
            {
                return _ActiveLogScopeItem;
            }
            set
            {
                _ActiveLogScopeItem = value;
                RaisePropertyChanged("ActiveLogScopeItem");
            }
        }

        #endregion
        #region LogContext

        private LogContext _LogContext;
        public LogContext LogContext
        {
            get
            {
                return _LogContext;
            }
            set
            {
                if (_LogContext != null)
                    _LogContext.PropertyChanged -= OnLogContextPropertyChanged;
                _LogContext = value;
                if (_LogContext != null)
                    _LogContext.PropertyChanged += OnLogContextPropertyChanged;
                RaisePropertyChanged("LogContext");
            }
        }

        #endregion
        #region CanSave

        public bool CanSave
        {
            get
            {
                if (this.ActiveLogScope != null)
                    return this.ActiveLogScope.DataRowStateIsDirty;
                return false;
            }
        }

        #endregion
        #region CanDelete

        public bool CanDelete
        {
            get
            {
                if ((this.ActiveLogScope != null) && (this.ActiveLogScope.LogScopeId != null))
                    return true;
                return false;
            }
        }

        #endregion
        #region CanAddTreeItem

        public bool CanAddTreeItem
        {
            get
            {
                if (this.ActiveServer != null)
                    return true;
                return false;
            }
        }

        #endregion
        #region CanSearch

        public bool CanSearch
        {
            get
            {
                if (this.ActiveLogScope == null)
                    return false;
                return true;
            }
        }

        #endregion
        #region HasActiveLogScope

        public bool HasActiveLogScope
        {
            get
            {
                if (this.ActiveLogScope == null)
                    return false;
                return true;
            }
        }

        #endregion
        #region EventItemListIsVisible

        public bool EventItemListIsVisible
        {
            get
            {
                return _EventItemListIsVisible;
            }
            set
            {
                _EventItemListIsVisible = value;
                RaisePropertyChanged("EventItemListIsVisible");
            }
        }

        #endregion

        #region AddTreeItemCommand

        public ICommand AddTreeItemCommand
        {
            get
            {
                return new MvxCommand(async () => await AddTreeItemAsync());
            }
        }

        #endregion
        #region AddTreeItemAsync

        public async Task AddTreeItemAsync()
        {
            LogScope item;
            TreeItem treeItem;

            treeItem = null;
            using (var busyManager = new BusyManager(this))
            {
                try
                {
                    if (this.ActiveServer != null)
                    {
                        item = new LogScope()
                        {
                            ServerConnectionId = this.ActiveServer.ServerConnectionId,
                            Name = "** New Log Scope **",
                        };
                        item = await item.SaveItemAsync();
                        await ReloadAsync();
                        treeItem = (from o in this.TreeItems
                                    where (o.ServerConnectionId == item.ServerConnectionId) && (o.LogScopeId == item.LogScopeId)
                                    select o).FirstOrDefault();
                    }
                }
                catch (System.Exception ex)
                {
                    await Sidvall.UI.SystemContext.Current.DialogManager.ShowErrorMessageAsync("Save Error", ex);
                }
            }
            if (treeItem != null)
                this.ActiveTreeItem = treeItem;
        }

        #endregion
        #region DeleteActiveTreeItemCommand

        public ICommand DeleteActiveTreeItemCommand
        {
            get
            {
                return new MvxCommand(async () => await DeleteActiveTreeItemAsync());
            }
        }

        #endregion
        #region DeleteActiveTreeItemAsync

        public async Task DeleteActiveTreeItemAsync()
        {
            await DeleteTreeItemAsync(this.ActiveTreeItem);
        }

        #endregion
        #region SaveActiveTreeItemCommand

        public ICommand SaveActiveTreeItemCommand
        {
            get
            {
                return new MvxCommand(async () => await SaveActiveTreeItemAsync());
            }
        }

        #endregion
        #region SaveActiveTreeItemAsync

        public async Task SaveActiveTreeItemAsync()
        {
            Task task = null;
            using (var busyManager = new BusyManager(this))
            {
                try
                {
                    if (this.ActiveLogScope != null)
                    {
                        this.ActiveLogScope = await this.ActiveLogScope.SaveItemAsync();
                    }
                    await ReloadAsync();
                }
                catch (System.Exception ex)
                {
                    task = Sidvall.UI.SystemContext.Current.DialogManager.ShowErrorMessageAsync("Save Error", ex);
                }
                if (task != null)
                    await task;
            }
        }

        #endregion
        #region SelectTreeItemCommand

        public ICommand SelectTreeItemCommand
        {
            get
            {
                return new MvxCommand(async () => await SelectTreeItemAsync());
            }
        }

        #endregion
        #region SelectTreeItemAsync

        public async Task SelectTreeItemAsync()
        {
            Task task = null;
            using (var busyManager = new BusyManager(this))
            {
                try
                {
                    if (this.ActiveTreeItem == null)
                    {
                        this.ActiveLogScope = null;
                    }
                    else if (this.ActiveTreeItem.IsServer)
                    {
                        this.ActiveServer = ServerConnection.GetServerConnection(this.ActiveTreeItem.ServerConnectionId);
                    }
                    else if (this.ActiveTreeItem.IsLogScope)
                    {
                        this.ActiveLogScope = await Sidvall.LogManager.UI.SystemContext.Current.DataPortal.LogScopeManager.GetItemAllIncludedAsync(this.ActiveTreeItem.ServerConnectionId, this.ActiveTreeItem.LogScopeId.Value);
                    }
                }
                catch (System.Exception ex)
                {
                    task = Sidvall.UI.SystemContext.Current.DialogManager.ShowErrorMessageAsync("Save Error", ex);
                }
                if (task != null)
                    await task;
            }
        }

        #endregion

        #region ShowEventItemListCommand

        public ICommand ShowEventItemListCommand
        {
            get
            {
                return new MvxCommand(ShowEventItemList);
            }
        }

        #endregion
        #region ShowEventItemList

        public void ShowEventItemList()
        {
            this.EventItemListIsVisible = true;
        }

        #endregion
        #region EditEventItemCommand

        public ICommand EditEventItemCommand
        {
            get
            {
                return new MvxCommand<LogScopeItem>(EditEventItem);
            }
        }

        #endregion
        #region EditEventItem

        public void EditEventItem(LogScopeItem item)
        {
            if (item == null)
                return;
            this.ActiveLogScopeItem = item;
            this.EventItemListIsVisible = false;
        }

        #endregion

        #region SearchCommand

        public ICommand SearchCommand
        {
            get
            {
                return new MvxCommand(async () => await SearchAsync());
            }
        }

        #endregion
        #region SearchAsync

        public async Task SearchAsync()
        {
            LogScopeItemCollection items;
            Task task = null;
            if (this.ActiveLogScope == null)
                return;
            using (var busyManager = new BusyManager(this))
            {
                try
                {
                    items = await Sidvall.LogManager.UI.SystemContext.Current.DataPortal.LogScopeItemManager.GetItemsAsync(this.ActiveLogScope.ServerConnectionId.Value,
                        this.ActiveLogScope.LogScopeId.Value, this.LogContext.EventTypeId, this.LogContext.Category, this.LogContext.Content, null, 300, null, null);
                    items.LoadEventTypes(this.EventTypes);
                    this.LogScopeItems = items;
                }
                catch (System.Exception ex)
                {
                    task = Sidvall.UI.SystemContext.Current.DialogManager.ShowErrorMessageAsync("Save Error", ex);
                }
                if (task != null)
                    await task;
            }
        }

        #endregion

        #region ReloadAsync

        public async Task ReloadAsync()
        {
            Task task = null;
            try
            {
                if (this.TreeItems == null)
                    return;
                await this.TreeItems.ReloadAsync();
                InitializeTitle();
            }
            catch (System.Exception ex)
            {
                task = Sidvall.UI.SystemContext.Current.DialogManager.ShowErrorMessageAsync("Save Error", ex);
            }
            if (task != null)
                await task;
        }

        #endregion
        #region StartAsync

        protected override async Task StartAsync()
        {
            _EventItemListIsVisible = true;

            this.Categories = Sidvall.Logging.LogCategoryManager.GetLogCategories();
            this.LogContext = new LogContext();
            this.TreeItems = TreeItemCollection.GetTreeItemCollection();
            InitializeTitle();

            await ReloadAsync();
        }

        #endregion

        #endregion
        #region Private Members

        private bool _EventItemListIsVisible = false;

        #region DeleteTreeItemAsync

        private async Task DeleteTreeItemAsync(TreeItem item)
        {
            Task task = null;
            if (item == null)
                return;
            if (item.IsServer)
                return;
            using (var busyManager = new Sidvall.Data.BusyManager(this))
            {
                try
                {
                    var message = await Sidvall.UI.SystemContext.Current.DialogManager.ShowYesNoMessageAsync("Remove item: " + item.Name, "Are you sure?",
                        Sidvall.UI.Dialogs.MessageType.Question, false);
                    if (!message.AnswerIsYes)
                        return;
                    if (item.IsLogScope)
                    {
                        await Sidvall.LogManager.SystemContext.Current.DataPortal.LogScopeManager.DeleteItemByPrimaryKeyAsync(item.ServerConnectionId,
                            item.LogScopeId.Value);
                        if ((this.ActiveLogScope != null) && (this.ActiveLogScope.LogScopeId == item.LogScopeId))
                            this.ActiveLogScope = null;
                        await ReloadAsync();
                    }
                }
                catch (System.Exception ex)
                {
                    task = Sidvall.UI.SystemContext.Current.DialogManager.ShowErrorMessageAsync("Save Error", ex);
                }
                if (task != null)
                    await task;
            }
        }

        #endregion
        #region InitializeTreeItem

        private void InitializeTreeItem()
        {
            RaisePropertyChanged("AddTreeItemCaption");
            RaisePropertyChanged("ActiveServer");
            RaisePropertyChanged("ActiveLogScope");
            RaisePropertyChanged("CanSave");
            RaisePropertyChanged("CanDelete");
            RaisePropertyChanged("CanAddTreeItem");
            RaisePropertyChanged("CanSearch");
            RaisePropertyChanged("HasActiveLogScope");
        }

        #endregion
        #region InitializeTitle

        private void InitializeTitle()
        {
            if (this.ActiveTreeItem == null)
            {
                this.Title = "Log Scopes";
            }
            else
            {
                this.Title = this.ActiveTreeItem.FullName;
            }
        }

        #endregion

        #region OnActiveLogScopePropertyChanged

        private void OnActiveLogScopePropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            RaisePropertyChanged("CanSave");
            RaisePropertyChanged("CanSearch");
        }

        #endregion
        #region OnLogContextPropertyChanged

        private void OnLogContextPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            RaisePropertyChanged("CanSearch");
        }

        #endregion

        #endregion
    }
}